Part 1: RNA

Load RNA samples

Out of 30 samples, we selected 17 for this study. These are the normal tissue samples form the control, the UVA and the UVA+SFN treatment groups. normal tissue samples from the UVB_UA groups as well as tumor samples were excluded from this analysis. Additionally, one of the control samples at Week 2 (baseline) was removed after outlier analysis.
7,219 genes with zero counts in > 80% (> 13 out of 18) of samples were removed. 17,202 out of 24,421 genes were left.

[1] 7219
[1] 17202

Transcripts per kilobase million (TPM) normalization

Next, we noramized the counts. To convert number of hits to the relative abundane of genes in each sample, we used transcripts per kilobase million (TPM) normalization, which is as following for the j-th sample:
1. normilize for gene length: a[i, j] = 1,000*count[i, j]/gene[i, j] length(bp)
2. normalize for seq depth (i.e. total count): a(i, j)/sum(a[, j])
3. multiply by one million
A very good comparison of normalization techniques can be found at the following video:
RPKM, FPKM and TPM, clearly explained

After the normalization, each sample’s total is 1M:

02w_CON_0 02w_SFN_0 02w_SFN_1 02w_UVB_0 02w_UVB_1 15w_CON_0 15w_CON_1 15w_SFN_0 15w_SFN_1 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 
15w_UVB_0 15w_UVB_1 25w_CON_0 25w_CON_1 25w_SFN_0 25w_SFN_1 25w_UVB_0 25w_UVB_1 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 

Top 100 most abundant RNA molecules

# Separate top 100 abundant genes
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[(nrow(tpm) - 99):nrow(tpm)]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p2 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p2)

Bottom 100 least abundant RNA molecules

tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[1:100]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p3 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p3)

Meta data

dmeta <- data.table(Sample = colnames(dt1)[-c(1:2)])

dmeta$time <- substr(x = dmeta$Sample,
                     start = 1,
                     stop = 3)
dmeta$time <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"))
dmeta$Week <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"),
                     labels = c("Week 2",
                                "Week 15",
                                "Week 25"))

dmeta$trt <- substr(x = dmeta$Sample,
                    start = 5,
                    stop = 7)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("CON", 
                               "UVB",
                               "SFN"))
dmeta$Treatment <- factor(dmeta$trt,
                          levels = c("CON", 
                                     "UVB",
                                     "SFN"),
                          labels = c("Negative Control",
                                     "Positive Control (UVB)",
                                     "Sulforaphane (SFN)"))

dmeta$Replica <- substr(x = dmeta$Sample,
                        start = 9,
                        stop = 9)
dmeta$Replica <- factor(dmeta$Replica,
                        levels = 0:1)

datatable(dmeta,
          options = list(pageLength = nrow(dmeta)))

PCA of TPM

NOTE: the distributions are skewed. To make them symmetric, log transformation is often applied. However, there is an issue of zeros. In this instance, we added a small values lambda[i] equal to 1/10 of the smallest non-zero value of i-th gene.

dm.tpm <- as.matrix(tpm[, -c(1:2), with = FALSE])
rownames(dm.tpm) <- tpm$Geneid

# # Remove 02w_CON_1 sample and redo PCA
# dm.tpm <- dm.tpm[, colnames(dm.tpm) != "02w_CON_1"]
# dmeta <- dmeta[dmeta$Sample != "02w_CON_1", ]

# Add lambdas to all values, then take a log
dm.ltpm <- t(apply(X = dm.tpm,
                      MARGIN = 1,
                      FUN = function(a) {
                        lambda <- min(a[a > 0])/10
                        log(a + lambda)
                      }))

# PCA----
m1 <- prcomp(t(dm.ltpm),
             center = TRUE,
             scale. = TRUE)

s1 <- summary(m1)
s1
Importance of components:
                           PC1     PC2     PC3      PC4      PC5      PC6      PC7      PC8      PC9
Standard deviation     66.5041 61.8206 45.2845 30.42909 28.24422 26.84136 25.01865 23.05989 22.08373
Proportion of Variance  0.2571  0.2222  0.1192  0.05383  0.04637  0.04188  0.03639  0.03091  0.02835
Cumulative Proportion   0.2571  0.4793  0.5985  0.65232  0.69869  0.74058  0.77696  0.80788  0.83623
                           PC10     PC11    PC12     PC13     PC14     PC15     PC16      PC17
Standard deviation     21.24391 20.87624 20.6980 20.28169 19.42403 19.14803 18.61200 2.085e-13
Proportion of Variance  0.02624  0.02534  0.0249  0.02391  0.02193  0.02131  0.02014 0.000e+00
Cumulative Proportion   0.86246  0.88780  0.9127  0.93662  0.95855  0.97986  1.00000 1.000e+00

Pareto chart of variance explained by principal components

imp <- data.table(PC = colnames(s1$importance),
                  Variance = 100*s1$importance[2, ],
                  Cumulative = 100*s1$importance[3, ])
imp$PC <- factor(imp$PC,
                 levels = imp$PC)
p1 <- ggplot(imp,
             aes(x = PC,
                 y = Variance)) +
  geom_bar(stat = "identity",
           fill = "grey",
           color = "black") +
  geom_line(aes(y = rescale(Cumulative,
                            to = c(min(Cumulative)*30/100,
                                   30)),
                group = rep(1, nrow(imp)))) +
  geom_point(aes(y = rescale(Cumulative,
                             to = c(min(Cumulative)*30/100,
                                    30)))) +
  scale_y_continuous("% Variance Explained",
                     breaks = seq(0, 30, by = 5),
                     labels = paste(seq(0, 30, by = 5),
                                    "%",
                                    sep = ""),
                     sec.axis = sec_axis(trans = ~.,
                                         name = "% Cumulative Variance",
                                         breaks = seq(0, 30, length.out = 5),
                                         labels = paste(seq(0, 100, length.out = 5),
                                                        "%",
                                                        sep = ""))) +
  scale_x_discrete("") +
  theme(axis.text.x = element_text(angle = 90,
                                   hjust = 1))

# Save for publication
tiff(filename = "tmp/pca_pareto.tiff",
     height = 6,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()

print(p1)

First 3 principal components, pairwise

# Biplot while keep only the most important variables (Javier)----
# Select PC-s to pliot (PC1 & PC2)
choices <- c(1:3)

# Scores, i.e. points (df.u)
dt.scr <- data.table(m1$x[, choices])
# Add grouping variables
dt.scr$trt <- dmeta$trt
dt.scr$time <- dmeta$time
dt.scr$sample <- dmeta$Sample

# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[choices], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))

p1 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  theme(legend.position = "none")
ggplotly(p1)


p2 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p2)


p3 <- ggplot(data = dt.scr,
             aes(x = PC2,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[2]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p3)


# Legend only
tmp <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point() +
  scale_color_discrete("Treatment") +
  scale_shape_discrete("Week")
p4 <- as_ggplot(get_legend(tmp))

# Save for publication
tiff(filename = "tmp/pca.tiff",
     height = 7,
     width = 9,
     units = 'in',
     res = 600,
     compression = "lzw+p")
grid.arrange(p1, p2, p3, p4, 
             nrow = 2)
graphics.off()

First 3 principal components, 3D

scatterplot3js(x = dt.scr$PC1, 
               y = dt.scr$PC2, 
               z = dt.scr$PC3, 
               color = as.numeric(dt.scr$trt),
               renderer = "auto",
               pch = dt.scr$sample,
               size = 0.1)

Differential expression analysis (DESeq2 pipeline)

Sources:
1. Analyzing RNA-seq data with DESeq2:Interactions
2. Bioconductor Question: DESeq2 time series analysis
We are testing a model with time*treatment interaction. The idea here is to find genes with significant interaction term. That would suggest that the gene expressiondifferences between the treatments depended on time. THere are several possible scenarios:
a. No difference between the negative control and the positive control groups at baseline, significant difference at the later time point. This will show the effect of the disease (UVB radiation, in this case).
b. Significant difference between the control groups at baseline, no difference at the later time point. Same as (a) above.
c. Differences between the positive control and the SFN-treated groups. Here, we are interested in the reversal of UVB effect. Again, the interaction term will need to be significant for the reasons described above.

# Relevel: make all comparisons with the positive control (UVB)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("UVB",
                               "CON",
                               "SFN"))

dtm<- as.matrix(dt1[, dmeta$Sample,
                    with = FALSE])
rownames(dtm) <- dt1$Geneid

dds <- DESeqDataSetFromMatrix(countData = dtm, 
                              colData = dmeta,
                              ~ time + trt + time:trt)
# If all samples contain zeros, geometric means cannot be
# estimated. Change default 'type = "ratio"' to 'type = "poscounts"'.
# Type '?DESeq2::estimateSizeFactors' for more details.
dds <- estimateSizeFactors(object = dds,
                           type = "poscounts")

# Run DESeq----
dds <- DESeq(object = dds,
             # test = "LRT",
             # reduced = ~ time + trt,
             fitType = "local",
             sfType = "ratio",
             parallel = FALSE)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
# NOTE (from DESeq help file, section Value):
# A DESeqDataSet object with results stored as metadata columns. 
# These results should accessed by calling the results function. 
# By default this will return the log2 fold changes and p-values
# for the last variable in the design formula. 
# See results for how to access results for other variables.
# In this case, the last term is the interaction term trt:time

# NOTE: 
# Likelihood ratio test (LRT) (chi-squared test) for GLM will only return 
# the results for the difference between the full and the reduced model

resultsNames(dds)
[1] "Intercept"       "time_15w_vs_02w" "time_25w_vs_02w" "trt_CON_vs_UVB"  "trt_SFN_vs_UVB" 
[6] "time15w.trtCON"  "time25w.trtCON"  "time15w.trtSFN"  "time25w.trtSFN" 
# Model matrix
mm1 <- model.matrix(~ time + trt + time:trt, dmeta)
mm1
   (Intercept) time15w time25w trtCON trtSFN time15w:trtCON time25w:trtCON time15w:trtSFN time25w:trtSFN
1            1       0       0      1      0              0              0              0              0
2            1       0       0      0      1              0              0              0              0
3            1       0       0      0      1              0              0              0              0
4            1       0       0      0      0              0              0              0              0
5            1       0       0      0      0              0              0              0              0
6            1       1       0      1      0              1              0              0              0
7            1       1       0      1      0              1              0              0              0
8            1       1       0      0      1              0              0              1              0
9            1       1       0      0      1              0              0              1              0
10           1       1       0      0      0              0              0              0              0
11           1       1       0      0      0              0              0              0              0
12           1       0       1      1      0              0              1              0              0
13           1       0       1      1      0              0              1              0              0
14           1       0       1      0      1              0              0              0              1
15           1       0       1      0      1              0              0              0              1
16           1       0       1      0      0              0              0              0              0
17           1       0       1      0      0              0              0              0              0
attr(,"assign")
[1] 0 1 1 2 2 3 3 3 3
attr(,"contrasts")
attr(,"contrasts")$time
[1] "contr.treatment"

attr(,"contrasts")$trt
[1] "contr.treatment"

Results

Effect of UVB at Week 2

res_con_uvb_week2 <- results(dds,
                             contrast = c(0,0,0,1,0,0,0,0,0),
                             alpha = 0.1)
res_con_uvb_week2 <- res_con_uvb_week2[order(res_con_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_con_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1546, 9%
LFC < 0 (down)     : 1537, 8.9%
outliers [1]       : 0, 0%
low counts [2]     : 2335, 14%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_con_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 3083
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_con_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)
graphics.off()

plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)

Protective effect of SFN at Week 2

res_sfn_uvb_week2 <- results(dds,
                             contrast = c(0,0,0,0,1,0,0,0,0),
                             alpha = 0.1)
res_sfn_uvb_week2 <- res_sfn_uvb_week2[order(res_sfn_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_sfn_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 26, 0.15%
LFC < 0 (down)     : 35, 0.2%
outliers [1]       : 0, 0%
low counts [2]     : 3669, 21%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 61
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL
graphics.off()

print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL

Genes that were significantly differentiated at both comparisons at Week 2

lgene.w2.con <- unique(res_con_uvb_week2@rownames[res_con_uvb_week2$padj < 0.1])
lgene.w2.sfn <- unique(res_sfn_uvb_week2@rownames[res_sfn_uvb_week2$padj < 0.1])
lgene.w2 <- lgene.w2.con[lgene.w2.con %in% lgene.w2.sfn]
lgene.w2 <- lgene.w2 [!is.na(lgene.w2 )]
lgene.w2
 [1] "Utrn"    "Stom"    "Tesc"    "Cited4"  "Cdhr1"   "Slc7a11" "Mki67"   "Cyp26b1" "Smc2"    "Mad2l1" 
[11] "Slc4a7"  "Ankrd23" "Ifitm3"  "Etv3"    "Pla2g4d" "Fetub"   "Kif11"   "Ccl6"    "Has3"    "Il19"   
[21] "A4galt"  "Otud1"   "Msn"     "Nqo1"    "Dbf4"    "Cblb"    "Tbc1d24" "Elmo2"   "Cd163"   "Esd"    
[31] "Rfx2"    "Gsta1"   "Slurp1"  "Arntl2"  "Vldlr"   "Tmem173" "Gpx2"    "Slfn9"   "Adh7"    "Sprr2i" 
[41] "Bcl2l15"

Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 2:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w2)) {
  out <- plotCounts(dds, 
                    gene = lgene.w2[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene.w2[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w",
                              "25w"),
                   labels = c("Week 2",
                              "Week 15",
                              "Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene.w2)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])
head(dmu)
List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did down-up-down trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did up-down-up trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

In many of these genes, UVB+SFN moved closer to UVB over time.

Heatmap for Week 2 differentially methylated genes

up.dn.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$up.dn]))
dn.up.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$dn.up]))
ll <- unique(c(up.dn.w2,
               dn.up.w2))
# 36 genes

con_uvb_week2 <- data.table(Geneid = res_con_uvb_week2@rownames,
                            log2FoldChange = res_con_uvb_week2@listData$log2FoldChange)

sfn_uvb_week2 <- data.table(Geneid = res_sfn_uvb_week2@rownames,
                            log2FoldChange = -res_sfn_uvb_week2@listData$log2FoldChange)

t1 <- merge(con_uvb_week2[con_uvb_week2$Geneid %in% ll, ],
            sfn_uvb_week2[sfn_uvb_week2$Geneid %in% ll, ],
            by = "Geneid")
colnames(t1)[2:3] <- c("Control vs. UVB",
                       "UVB vs. SFN+UVB")
t1 <- t1[order(t1$`Control vs. UVB`,
               decreasing = TRUE), ]
write.csv(t1,
          file = "tmp/w2_sign_changes.csv",
          row.names = FALSE)

ll <- melt.data.table(data = t1,
                      id.vars = 1,
                      measure.vars = 2:3,
                      variable.name = "Comparison",
                      value.name = "Gene Expression Diff")
ll$Comparison <- factor(ll$Comparison,
                        levels = c("Control vs. UVB",
                                   "UVB vs. SFN+UVB"))
lvls <- ll[ll$Comparison == "Control vs. UVB", ]
ll$Geneid <- factor(ll$Geneid,
                    levels = lvls$Geneid[order(lvls$`Gene Expression Diff`)])

# Add dendrogram----
dt.dndr <- data.frame(t1[Geneid %in% levels(ll$Geneid), ])
rownames(dt.dndr) <- dt.dndr$Gene
dt.dndr <- dt.dndr[, -1]

# Compute distances between genes----
sampleDists <- dist(dt.dndr)

# Make dendrogram data----
dhc <- as.dendrogram(hclust(d = sampleDists),
                     horiz = TRUE)
ddata <- dendro_data(dhc, 
                     type = "rectangle")

# Segment data----
dtp1 <- segment(ddata)

# Hitmap data----
dtp2 <- ll
dtp2$Geneid <- factor(dtp2$Geneid,
                      levels = ddata$labels$label)

offset.size <- 4

p1 <- ggplot(data = dtp2) +
  coord_polar("y",
              start = -0.3,
              direction = -1) +
  geom_tile(aes(x =  as.numeric(Comparison),
                y = Geneid, 
                fill = `Gene Expression Diff`),
            color = "white") +
  geom_text(data = dtp2[Comparison == "Control vs. UVB", ],
            aes(x = rep(1.75,
                        nlevels(Geneid)),
                y = Geneid,
                angle = 90 + seq(from = 30,
                                 to = 330,
                                 length.out = nlevels(Geneid))[as.numeric(Geneid)] + 
                  offset.size,
                label = unique(Geneid)),
            hjust = 0) +
  geom_text(data = dtp2[Geneid == levels(dtp2$Geneid)[1], ],
            aes(x = 1:nlevels(Comparison),
                y = rep(-offset.size,
                        nlevels(Comparison)),
                angle = 0,
                label = levels(Comparison)),
            hjust = 1,
            size = 5) +
  scale_fill_gradient2(low = "red", 
                       high = "green", 
                       mid = "grey", 
                       midpoint = 0, 
                       name = "") +
  scale_y_discrete("",
                   expand = c(0, 0)) +
  theme(plot.title = element_text(hjust = 0.5),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_blank(),
        legend.position = "bottom",
        legend.text = element_text(size = 15),
        legend.direction = "horizontal",
        legend.key.width = unit(1, "in"),
        legend.key.height = unit(0.3, "in")) +
  geom_segment(data = dtp1,
               aes(x = -sqrt(y) + 0.5,
                   y = x, 
                   xend = -sqrt(yend) + 0.5,
                   yend = xend),
               size = 1) 

tiff(filename = "tmp/skin_ubv_w2_sfn_hitmap_with_phylo.tiff",
     height = 8,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Venn Diagram, Week 2

# 1. Ctrl vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 1546, 9%
# LFC < 0 (down)     : 1537, 8.9%
# 23 genes down-up-down

# 2. SFN+UVB vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 26, 0.15%
# LFC < 0 (down)     : 35, 0.2%
# 13 gens up-down-up

p1 <- ggplot() +
  geom_circle(aes(x0 = c(1, 2, 1, 2),
                  y0 = c(1, 1, 4, 4),
                  r = rep(1, 4),
                  color = factor(c(2, 1, 1, 2))),
              size = 2) +
  geom_text(aes(x = rep(c(0.5, 1.5, 2.5), 2),
                y = rep(c(1, 4), each = 3),
                label = format(c(26, 13, 35, 1546, 23, 1537),
                               big.mark = ","))) +
  scale_color_manual(values = c("green", "red")) +
  theme_void() +
  theme(legend.position = "none")

tiff(filename = "tmp/skin_ubv_sfn_w2_venn.tiff",
     height = 6,
     width = 4,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Effect of UVB at Week 15

res_con_uvb_week15 <- results(dds,
                             contrast = c(0,1,0,1,0,0,0,0,0),
                             alpha = 0.1)
res_con_uvb_week15 <- res_con_uvb_week15[order(res_con_uvb_week15$padj,
                                                   decreasing = FALSE),]
summary(res_con_uvb_week15)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1449, 8.4%
LFC < 0 (down)     : 1481, 8.6%
outliers [1]       : 0, 0%
low counts [2]     : 3669, 21%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.1?
sum(res_con_uvb_week15$padj < 0.1, 
    na.rm = TRUE)
[1] 2930
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w15_con_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plotMA(res_con_uvb_week15,
             main = "Control vs. UVB at Week 15",
             alpha = 0.8)
graphics.off()

plotMA(res_con_uvb_week15,
             main = "Control vs. UVB at Week 15",
             alpha = 0.8)

Protective effect of SFN at Week 15

res_sfn_uvb_week15 <- results(dds,
                             contrast = c(0,1,0,0,1,0,0,0,0),
                             alpha = 0.1)
res_sfn_uvb_week15 <- res_sfn_uvb_week15[order(res_sfn_uvb_week15$padj,
                                                   decreasing = FALSE),]
summary(res_sfn_uvb_week15)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 27, 0.16%
LFC < 0 (down)     : 9, 0.052%
outliers [1]       : 0, 0%
low counts [2]     : 6337, 37%
(mean count < 36)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week15$padj < 0.1, 
    na.rm = TRUE)
[1] 36
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(plotMA(res_sfn_uvb_week15,
             main = "UVB+SFN vs UVB at Week 15",
             alpha = 0.8))
NULL
graphics.off()

print(plotMA(res_sfn_uvb_week15,
             main = "UVB+SFN vs UVB at Week 15",
             alpha = 0.8))
NULL

Genes that were significantly differentiated at both comparisons at Week 15

lgene.w15.con <- unique(res_con_uvb_week15@rownames[res_con_uvb_week15$padj < 0.1])
lgene.w15.sfn <- unique(res_sfn_uvb_week15@rownames[res_sfn_uvb_week15$padj < 0.1])
lgene.w15 <- lgene.w15.con[lgene.w15.con %in% lgene.w15.sfn]
lgene.w15 <- lgene.w15 [!is.na(lgene.w15 )]
lgene.w15
 [1] "Sectm1a"       "Gigyf1"        "Utrn"          "Abcc5"         "H2-M2"         "Tcirg1"       
 [7] "Cited4"        "Tbc1d2b"       "Tesc"          "Rabgap1l"      "Ankrd37"       "Hsd3b7"       
[13] "H2-T10"        "Kmt2a"         "Hsph1"         "Etv3"          "Pnn"           "Creld1"       
[19] "Oas3"          "Scmh1"         "Lipg"          "Il19"          "Samd9l"        "Uba7"         
[25] "2410131K14Rik" "Sprr2i"        "Cyp1b1"        "Vldlr"         "Nqo1"          "Nfkbiz"       
[31] "Gpx2"          "Fetub"         "Sprr2f"       

Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 15:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w15)) {
  out <- plotCounts(dds, 
                    gene = lgene.w15[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene.w15[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w",
                              "25w"),
                   labels = c("Week 2",
                              "Week 15",
                              "Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene.w15)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])
head(dmu)
List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did down-up-down trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$up.dn]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$up.dn]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did up-down-up trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$dn.up]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$dn.up]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

Heatmap for Week 15 differentially methylated genes

up.dn.w15 <- unique(as.character(dmu.w15$Geneid[dmu.w15$up.dn]))
dn.up.w15 <- unique(as.character(dmu.w15$Geneid[dmu.w15$dn.up]))
ll <- unique(c(up.dn.w15,
               dn.up.w15))
# 16 genes

con_uvb_week15 <- data.table(Geneid = res_con_uvb_week15@rownames,
                            log2FoldChange = res_con_uvb_week15@listData$log2FoldChange)

sfn_uvb_week15 <- data.table(Geneid = res_sfn_uvb_week15@rownames,
                            log2FoldChange = -res_sfn_uvb_week15@listData$log2FoldChange)

t1 <- merge(con_uvb_week15[con_uvb_week15$Geneid %in% ll, ],
            sfn_uvb_week15[sfn_uvb_week15$Geneid %in% ll, ],
            by = "Geneid")
colnames(t1)[2:3] <- c("Control vs. UVB",
                       "UVB vs. SFN+UVB")
t1 <- t1[order(t1$`Control vs. UVB`,
               decreasing = TRUE), ]
write.csv(t1,
          file = "tmp/w15_sign_changes.csv",
          row.names = FALSE)

ll <- melt.data.table(data = t1,
                      id.vars = 1,
                      measure.vars = 2:3,
                      variable.name = "Comparison",
                      value.name = "Gene Expression Diff")
ll$Comparison <- factor(ll$Comparison,
                        levels = c("Control vs. UVB",
                                   "UVB vs. SFN+UVB"))
lvls <- ll[ll$Comparison == "Control vs. UVB", ]
ll$Geneid <- factor(ll$Geneid,
                    levels = lvls$Geneid[order(lvls$`Gene Expression Diff`)])

# Add dendrogram----
dt.dndr <- data.frame(t1[Geneid %in% levels(ll$Geneid), ])
rownames(dt.dndr) <- dt.dndr$Gene
dt.dndr <- dt.dndr[, -1]

# Compute distances between genes----
sampleDists <- dist(dt.dndr)

# Make dendrogram data----
dhc <- as.dendrogram(hclust(d = sampleDists),
                     horiz = TRUE)
ddata <- dendro_data(dhc, 
                     type = "rectangle")

# Segment data----
dtp1 <- segment(ddata)

# Hitmap data----
dtp2 <- ll
dtp2$Geneid <- factor(dtp2$Geneid,
                      levels = ddata$labels$label)

offset.size <- 4

p1 <- ggplot(data = dtp2) +
  coord_polar("y",
              start = -0.3,
              direction = -1) +
  geom_tile(aes(x =  as.numeric(Comparison),
                y = Geneid, 
                fill = `Gene Expression Diff`),
            color = "white") +
  geom_text(data = dtp2[Comparison == "Control vs. UVB", ],
            aes(x = rep(1.75,
                        nlevels(Geneid)),
                y = Geneid,
                angle = 90 + seq(from = 30,
                                 to = 330,
                                 length.out = nlevels(Geneid))[as.numeric(Geneid)] + 
                  offset.size,
                label = unique(Geneid)),
            hjust = 0) +
  geom_text(data = dtp2[Geneid == levels(dtp2$Geneid)[1], ],
            aes(x = 1:nlevels(Comparison),
                y = rep(-offset.size,
                        nlevels(Comparison)),
                angle = 0,
                label = levels(Comparison)),
            hjust = 1,
            size = 5) +
  scale_fill_gradient2(low = "red", 
                       high = "green", 
                       mid = "grey", 
                       midpoint = 0, 
                       name = "") +
  scale_y_discrete("",
                   expand = c(0, 0)) +
  theme(plot.title = element_text(hjust = 0.5),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_blank(),
        legend.position = "bottom",
        legend.text = element_text(size = 15),
        legend.direction = "horizontal",
        legend.key.width = unit(1, "in"),
        legend.key.height = unit(0.3, "in")) +
  geom_segment(data = dtp1,
               aes(x = -sqrt(y) + 0.5,
                   y = x, 
                   xend = -sqrt(yend) + 0.5,
                   yend = xend),
               size = 1) 

tiff(filename = "tmp/skin_ubv_w15_sfn_hitmap_with_phylo.tiff",
     height = 8,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Venn Diagram, Week 15

# 1. Ctrl vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 1449, 8.4%
# LFC < 0 (down)     : 1481, 8.6%
# 23 genes down-up-down

# 2. SFN+UVB vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 27, 0.16%
# LFC < 0 (down)     : 9, 0.052%
# 13 gens up-down-up

p1 <- ggplot() +
  geom_circle(aes(x0 = c(1, 2, 1, 2),
                  y0 = c(1, 1, 4, 4),
                  r = rep(1, 4),
                  color = factor(c(2, 1, 1, 2))),
              size = 2) +
  geom_text(aes(x = rep(c(0.5, 1.5, 2.5), 2),
                y = rep(c(1, 4), each = 3),
                label = format(c(27, 8, 9, 1449, 8, 1481),
                               big.mark = ","))) +
  scale_color_manual(values = c("green", "red")) +
  theme_void() +
  theme(legend.position = "none")

tiff(filename = "tmp/skin_ubv_sfn_w2_venn.tiff",
     height = 6,
     width = 4,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Interactions terms

Tests if the effect of NOT treating with UVB vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_con_uvb_week <- results(dds, 
                                name = "time15w.trtCON",
                                alpha = 0.1)
res_int_con_uvb_week <- res_int_con_uvb_week[order(res_int_con_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_con_uvb_week)
log2 fold change (MLE): time15w.trtCON 
Wald test p-value: time15w.trtCON 
DataFrame with 17202 rows and 6 columns
                  baseMean     log2FoldChange             lfcSE               stat               pvalue
                 <numeric>          <numeric>         <numeric>          <numeric>            <numeric>
Ces2g     1233.64052107766   1.65919128471462 0.219706072210844   7.55186813008224 4.29058805762623e-14
Chil4     729.990857182023  -11.1293956873127  1.54858690264879  -7.18680731980641 6.63239033912628e-13
Tiparp    683.339510901133   1.49955960160452 0.248262587560916   6.04021579061555 1.53908254415537e-09
Slc25a37  391.064324378349  -1.45460152768479 0.244923011988198  -5.93901534966785  2.8673902141708e-09
H2-M2      206.94506916379  -1.98012352045144  0.34512732806993  -5.73737099152641 9.61574727613009e-09
...                    ...                ...               ...                ...                  ...
Gpm6b     6.76909966446477  -3.26887203161146  1.55193921192052  -2.10631447836558   0.0351770444831032
Tlr7      1.11233183040672  0.165798521539309  3.90101579949831 0.0425013714532075    0.966099018478313
Arhgap6   1.55558065988387  0.701543913331167  2.69733929865055   0.26008738080602    0.794796371714883
Spry3     2.92590454614356 -0.756574618876826     2.19462355565 -0.344740042969577    0.730289811494176
Zf12     0.240459283234895   1.53995508412402  7.75773006704587  0.198505886491927    0.842649279637729
                         padj
                    <numeric>
Ces2g    5.23408837149824e-10
Chil4    4.04542648735007e-09
Tiparp   6.25842265205047e-06
Slc25a37 8.74482330566741e-06
H2-M2    2.34605002043022e-05
...                       ...
Gpm6b                      NA
Tlr7                       NA
Arhgap6                    NA
Spry3                      NA
Zf12                       NA
summary(res_int_con_uvb_week)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 62, 0.36%
LFC < 0 (down)     : 81, 0.47%
outliers [1]       : 0, 0%
low counts [2]     : 5003, 29%
(mean count < 14)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_int_con_uvb_week$padj < 0.1, 
    na.rm = TRUE)
[1] 143
# MA plot
print(plotMA(res_int_con_uvb_week,
             main = "(Control vs. UVB) x TIme Interaction",
             alpha = 0.9))
NULL

Tests if the effect of treating with UVB+SFN vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_sfn_uvb_week <- results(dds, 
                                name = "time15w.trtSFN",
                                alpha = 0.1)
res_int_sfn_uvb_week <- res_int_sfn_uvb_week[order(res_int_sfn_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_sfn_uvb_week)
summary(res_int_sfn_uvb_week)

# How many adjusted p-values were less than 0.05?
sum(res_int_sfn_uvb_week$padj < 0.1, 
    na.rm = TRUE)

# MA plot
print(plotMA(res_int_sfn_uvb_week))

# NOTE: same as 
# res <- results(dds, 
#                   alpha = 0.05)
# res <- res[order(res$padj, decreasing = FALSE),]
# res

NOTE: By default, the results(dds)* prints the results for the last level of the last term, i.e. here it was for for the interaction term SFN vs. UVB at Week 15 vs. Week 2.

Genes with both interactions being significant

lgene.con <- unique(res_int_con_uvb_week@rownames[res_int_con_uvb_week$padj < 0.1])
lgene.sfn <- unique(res_int_sfn_uvb_week@rownames[res_int_sfn_uvb_week$padj < 0.1])
lgene <- lgene.con[lgene.con %in% lgene.sfn]
lgene <- lgene[!is.na(lgene)]
lgene

Plot of DESeq-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene)) {
  out <- plotCounts(dds, 
                    gene = lgene[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w"),
                   labels = c("Week 2",
                              "Week 15"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])

p1 <- ggplot(dp1,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

Compare to the plot of TPM-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Examine TPM values for the same genes
tmp <- tpm[Geneid %in% lgene, ]
tmp$Geneid <- factor(tmp$Geneid,
                     levels = lgene)
tmp <- melt.data.table(data = tmp,
                       id.vars = 1,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")
tmp <- merge(dmeta,
             tmp,
             by = "Sample")

p1 <- ggplot(tmp,
             aes(x = Week,
                 y = TPM,
                 fill = Treatment,
                 group = Treatment)) +
  facet_wrap(~ Geneid,
             scales = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black")+
  scale_x_discrete("")
plot(p1)

Session Information

sessionInfo()
LS0tDQp0aXRsZTogIlNraW4gVVZCIFNLSDEgbW91c2UgbW9kZWwgdHJlYXRlZCB3aXRoIFNGTiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCiMgUGFydCAxOiBSTkENCmBgYHtyIGhlYWRlciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIHdhcm5pbmcgID1GQUxTRX0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpDQoNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKERUKQ0KcmVxdWlyZShERVNlcTIpDQpyZXF1aXJlKHJlYWR4bCkNCnJlcXVpcmUoQmlvY1BhcmFsbGVsKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKHRocmVlanMpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUoZ3JpZEV4dHJhKQ0KcmVxdWlyZShnZ3B1YnIpDQpyZXF1aXJlKGdnZGVuZHJvKQ0KcmVxdWlyZShnZ2ZvcmNlKQ0KDQojIE5PVEU6IG9uIERFU2VxMiBPdXRwdXQ6ICdiYXNlTWVhbicgaXMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzLCANCiMgZGl2aWRlZCBieSB0aGUgc2l6ZSBmYWN0b3JzLCB0YWtlbiBvdmVyIGFsbCBzYW1wbGVzIGluIHRoZSBERVNlcURhdGFTZXQNCmBgYA0KDQojIyBMb2FkIFJOQSBzYW1wbGVzDQpPdXQgb2YgMzAgc2FtcGxlcywgd2Ugc2VsZWN0ZWQgMTcgZm9yIHRoaXMgc3R1ZHkuIFRoZXNlIGFyZSB0aGUgbm9ybWFsIHRpc3N1ZSBzYW1wbGVzIGZvcm0gdGhlIGNvbnRyb2wsIHRoZSBVVkEgYW5kIHRoZSBVVkErU0ZOIHRyZWF0bWVudCBncm91cHMuIG5vcm1hbCB0aXNzdWUgc2FtcGxlcyBmcm9tIHRoZSBVVkJfVUEgZ3JvdXBzIGFzIHdlbGwgYXMgdHVtb3Igc2FtcGxlcyB3ZXJlIGV4Y2x1ZGVkIGZyb20gdGhpcyBhbmFseXNpcy4gQWRkaXRpb25hbGx5LCBvbmUgb2YgdGhlIGNvbnRyb2wgc2FtcGxlcyBhdCBXZWVrIDIgKGJhc2VsaW5lKSB3YXMgcmVtb3ZlZCBhZnRlciBvdXRsaWVyIGFuYWx5c2lzLiAgICANCjcsMjE5IGdlbmVzIHdpdGggemVybyBjb3VudHMgaW4gPiA4MCUgKD4gMTMgb3V0IG9mIDE4KSBvZiBzYW1wbGVzIHdlcmUgcmVtb3ZlZC4gMTcsMjAyIG91dCBvZiAyNCw0MjEgZ2VuZXMgd2VyZSBsZWZ0LiANCiAgICAgICAgIA0KYGBge3IgZGF0YV9ybmEsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIExvYWQgZGF0YS0tLS0NCmR0MCA8LSBmcmVhZCgiZGF0YS9yZW55aV9kZWR1cF9ybmFzZXFfZGF0YS9mZWF0dXJlc2NvdW50c191dmItc2tpbl9kZWR1cF9yZW55aV8yLTktMjAxOC5jc3YiLA0KICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQojIFJlbW92ZSB1bnVzZWQgY29sdW1ucy0tLS0NCmR0MSA8LSBkdDBbLCBjKDEsIDY6bmNvbChkdDApKSwgd2l0aCA9IEZBTFNFXQ0KDQpjbmFtZXMgPC0gY29sbmFtZXMoZHQxKVstYygxOjIpXQ0KY25hbWVzIDwtIGdzdWIoeCA9IGNuYW1lcywNCiAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLmRlZHVwLmJhbSIsDQogICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KY29sbmFtZXMoZHQxKVstYygxOjIpXSA8LSBjbmFtZXMNCg0KIyBBVFRFTlRJT04hIEluIHRoaXMgYW5hbHlzaXMsIHdlIHdpbGwgb25seSBleGFtaW5lIGNvbnRyb2xzIGFuZCBTRk4NCiMgQWxzbywgcmVtb3ZlZCBjYW5jZXIgY2VsbCBzYW1wbGVzDQp0bmFtZXMgPC0gc3Vic3RyKHggPSBjb2xuYW1lcyhkdDEpLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSAzLA0KICAgICAgICAgICAgICAgICBzdG9wID0gMykNCg0KZ25hbWVzIDwtIHN1YnN0cih4ID0gY29sbmFtZXMoZHQxKSwgDQogICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQoNCmR0MSA8LSBkdDFbLCBnbmFtZXMgJWluJSBjKCJpZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAidGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iICkgJg0KICAgICAgICAgICAgIHRuYW1lcyAhPSAidCIsDQogICAgICAgICAgIHdpdGggPSBGQUxTRV0NCiMgMTggc2FtcGxlcyBsZWZ0DQoNCiMgUmVtb3ZlIHNhbXBsZSAnMDJ3X0NPTl8xJyBhcyBhbiBvdXRsaWVyDQojIFNlZSAnc2tpbl91dmJfc2ZuX2V4Y2x1ZGVfY29uMncxX3YxJyBmb3IgZGV0YWlscw0KZHQxIDwtIGR0MVssIGNvbG5hbWVzKGR0MSkgIT0gIjAyd19DT05fMSIsIHdpdGggPSBGQUxTRV0NCg0KIyBSZW1vdmUgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBpbiA+IDgwJSAoPiAxMyBvdXQgb2YgMTcpIG9mIHNhbXBsZXMNCnRtcCA8LSBkdDFbLCAtYygxOjIpXSA9PSAwDQp0bXAgPC0gcm93U3Vtcyh0bXApID4gMTMNCnN1bSh0bXApDQoNCmR0MSA8LSBkcm9wbGV2ZWxzKGR0MVshdG1wLCBdKQ0KbnJvdyhkdDEpDQojIDE3LDIwMiBvdXQgb2YgMjQsNDIxIGdlbmVzIGxlZnQNCg0KZGF0YXRhYmxlKGhlYWQoZHQxLCAxMCksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApLA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgMTogZmlyc3QgMTAgcm93cyBvZiB0aGUgY291bnQgdGFibGUiKQ0KYGBgDQoNCiMjIFRyYW5zY3JpcHRzIHBlciBraWxvYmFzZSBtaWxsaW9uIChUUE0pIG5vcm1hbGl6YXRpb24NCk5leHQsIHdlIG5vcmFtaXplZCB0aGUgY291bnRzLiBUbyBjb252ZXJ0IG51bWJlciBvZiBoaXRzIHRvICB0aGUgcmVsYXRpdmUgYWJ1bmRhbmUgb2YgZ2VuZXMgaW4gZWFjaCBzYW1wbGUsIHdlIHVzZWQgKioqdHJhbnNjcmlwdHMgcGVyIGtpbG9iYXNlIG1pbGxpb24gKFRQTSkqKiogbm9ybWFsaXphdGlvbiwgd2hpY2ggaXMgYXMgZm9sbG93aW5nIGZvciB0aGUgai10aCBzYW1wbGU6ICAgICAgIA0KMS4gbm9ybWlsaXplIGZvciBnZW5lIGxlbmd0aDogYVtpLCBqXSA9IDEsMDAwKmNvdW50W2ksIGpdL2dlbmVbaSwgal0gbGVuZ3RoKGJwKSAgICAgDQoyLiBub3JtYWxpemUgZm9yIHNlcSBkZXB0aCAoaS5lLiB0b3RhbCBjb3VudCk6IGEoaSwgaikvc3VtKGFbLCBqXSkgICAgIA0KMy4gbXVsdGlwbHkgYnkgb25lIG1pbGxpb24gICAgIA0KQSB2ZXJ5IGdvb2QgY29tcGFyaXNvbiBvZiBub3JtYWxpemF0aW9uIHRlY2huaXF1ZXMgY2FuIGJlIGZvdW5kIGF0IHRoZSBmb2xsb3dpbmcgdmlkZW86ICAgIA0KW1JQS00sIEZQS00gYW5kIFRQTSwgY2xlYXJseSBleHBsYWluZWRdKGh0dHBzOi8vd3d3LnJuYS1zZXFibG9nLmNvbS9ycGttLWZwa20tYW5kLXRwbS1jbGVhcmx5LWV4cGxhaW5lZC8pDQogICAgIA0KQWZ0ZXIgdGhlIG5vcm1hbGl6YXRpb24sIGVhY2ggc2FtcGxlJ3MgdG90YWwgaXMgMU06DQogICAgIA0KYGBge3IgdHBtLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KIyBOb3JtYWxpemUgY291bnRzIHRvIFRQTQ0KdG1wIDwtIDEwMDAqZHQxWywgMzpuY29sKGR0MSldL2R0MSRMZW5ndGgNCnRwbSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGR0MSRHZW5laWQsDQogICAgICAgICAgICAgICAgICBMZW5ndGggPSBkdDEkTGVuZ3RoLA0KICAgICAgICAgICAgICAgICAgYXBwbHkodG1wLA0KICAgICAgICAgICAgICAgICAgICAgICAgMiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGEpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgMTBeNiooYS9zdW0oYSkpDQogICAgICAgICAgICAgICAgICAgICAgICB9KSkNCmNvbFN1bXModHBtWywgLWMoMToyKV0pDQoNCmZvcm1hdFJvdW5kKGRhdGF0YWJsZShoZWFkKHRwbSwgMTApLA0KICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSwNCiAgICAgICAgICAgICAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIDI6IHRyYW5zY3JpcHRzIHBlciBraWxvYmFzZSBtaWxsaW9uIChUUE0pIG5vcm1hbGl6ZWQgY291bnRzIiksDQogICAgICAgICAgICBjb2x1bW5zID0gMzpuY29sKHRwbSksDQogICAgICAgICAgICBkaWdpdHMgPSAyKQ0KDQojIFRvdGFsIFRQTQ0KdG90YWwgPC0gcm93U3Vtcyh0cG1bLCAzOm5jb2wodHBtKV0pDQoNCiMgU29ydCBnZW5lcyBieSByZWxhdGl2ZSBhYnVuZGFuY3kNCnRwbSRHZW5laWQgPC0gZmFjdG9yKHRwbSRHZW5laWQgLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdHBtJEdlbmVpZFtvcmRlcih0b3RhbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKV0pDQpgYGANCg0KIyBUb3AgMTAwIG1vc3QgYWJ1bmRhbnQgUk5BIG1vbGVjdWxlcw0KYGBge3IgbW9zdF9hYnVuZGFudH0NCiMgU2VwYXJhdGUgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KdG1wIDwtIGRyb3BsZXZlbHModHBtW0dlbmVpZCAlaW4lIGxldmVscyh0cG0kR2VuZWlkKVsobnJvdyh0cG0pIC0gOTkpOm5yb3codHBtKV1dKQ0KDQp0bXAgPC0gbWVsdC5kYXRhLnRhYmxlKGRhdGEgPSB0bXAsDQogICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxOjIsDQogICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDM6bmNvbCh0bXApLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiVFBNIikNCg0KdG1wJFdlZWsgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCnRtcCRXZWVrIDwtIGZhY3Rvcih0bXAkV2VlaywNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUodG1wJFdlZWspKQ0KDQoNCnRtcCRUcmVhdG1lbnQgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQp0bXAkVHJlYXRtZW50IDwtIGZhY3Rvcih0bXAkVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQoNCnRtcCRSZXBsaWNhIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQp0bXAkUmVwbGljYSA8LSBmYWN0b3IodG1wJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQojIFBsb3QgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KcDIgPC0gZ2dwbG90KHRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFRQTSwNCiAgICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBXZWVrKSkgKw0KICAjIGZhY2V0X3dyYXAofiBTZXgsIG5yb3cgPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KZ2dwbG90bHkocDIpDQpgYGANCg0KIyBCb3R0b20gMTAwIGxlYXN0IGFidW5kYW50IFJOQSBtb2xlY3VsZXMNCmBgYHtyIGxlYXN0X2FidW5kYW50fQ0KdG1wIDwtIGRyb3BsZXZlbHModHBtW0dlbmVpZCAlaW4lIGxldmVscyh0cG0kR2VuZWlkKVsxOjEwMF1dKQ0KDQp0bXAgPC0gbWVsdC5kYXRhLnRhYmxlKGRhdGEgPSB0bXAsDQogICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxOjIsDQogICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDM6bmNvbCh0bXApLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiVFBNIikNCg0KdG1wJFdlZWsgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCnRtcCRXZWVrIDwtIGZhY3Rvcih0bXAkV2VlaywNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUodG1wJFdlZWspKQ0KDQoNCnRtcCRUcmVhdG1lbnQgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQp0bXAkVHJlYXRtZW50IDwtIGZhY3Rvcih0bXAkVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQoNCnRtcCRSZXBsaWNhIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQp0bXAkUmVwbGljYSA8LSBmYWN0b3IodG1wJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQojIFBsb3QgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KcDMgPC0gZ2dwbG90KHRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFRQTSwNCiAgICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBXZWVrKSkgKw0KICAjIGZhY2V0X3dyYXAofiBTZXgsIG5yb3cgPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KZ2dwbG90bHkocDMpDQpgYGANCg0KIyBNZXRhIGRhdGENCmBgYHtyIG1ldGF9DQpkbWV0YSA8LSBkYXRhLnRhYmxlKFNhbXBsZSA9IGNvbG5hbWVzKGR0MSlbLWMoMToyKV0pDQoNCmRtZXRhJHRpbWUgPC0gc3Vic3RyKHggPSBkbWV0YSRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDEsDQogICAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCmRtZXRhJHRpbWUgPC0gZmFjdG9yKGRtZXRhJHRpbWUsDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCIwMnciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpKQ0KZG1ldGEkV2VlayA8LSBmYWN0b3IoZG1ldGEkdGltZSwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IiksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXZWVrIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDI1IikpDQoNCmRtZXRhJHRydCA8LSBzdWJzdHIoeCA9IGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCmRtZXRhJHRydCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQpkbWV0YSRUcmVhdG1lbnQgPC0gZmFjdG9yKGRtZXRhJHRydCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJOZWdhdGl2ZSBDb250cm9sIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zaXRpdmUgQ29udHJvbCAoVVZCKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN1bGZvcmFwaGFuZSAoU0ZOKSIpKQ0KDQpkbWV0YSRSZXBsaWNhIDwtIHN1YnN0cih4ID0gZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQpkbWV0YSRSZXBsaWNhIDwtIGZhY3RvcihkbWV0YSRSZXBsaWNhLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQpkYXRhdGFibGUoZG1ldGEsDQogICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IG5yb3coZG1ldGEpKSkNCmBgYA0KDQojIFBDQSBvZiBUUE0NCk5PVEU6IHRoZSBkaXN0cmlidXRpb25zIGFyZSBza2V3ZWQuIFRvIG1ha2UgdGhlbSBzeW1tZXRyaWMsIGxvZyB0cmFuc2Zvcm1hdGlvbiBpcyBvZnRlbiBhcHBsaWVkLiBIb3dldmVyLCB0aGVyZSBpcyBhbiBpc3N1ZSBvZiB6ZXJvcy4gSW4gdGhpcyBpbnN0YW5jZSwgd2UgYWRkZWQgYSBzbWFsbCB2YWx1ZXMgKioqbGFtYmRhW2ldKioqIGVxdWFsIHRvIDEvMTAgb2YgdGhlIHNtYWxsZXN0IG5vbi16ZXJvIHZhbHVlIG9mICppKi10aCBnZW5lLiANCmBgYHtyIHBjYX0NCmRtLnRwbSA8LSBhcy5tYXRyaXgodHBtWywgLWMoMToyKSwgd2l0aCA9IEZBTFNFXSkNCnJvd25hbWVzKGRtLnRwbSkgPC0gdHBtJEdlbmVpZA0KDQojICMgUmVtb3ZlIDAyd19DT05fMSBzYW1wbGUgYW5kIHJlZG8gUENBDQojIGRtLnRwbSA8LSBkbS50cG1bLCBjb2xuYW1lcyhkbS50cG0pICE9ICIwMndfQ09OXzEiXQ0KIyBkbWV0YSA8LSBkbWV0YVtkbWV0YSRTYW1wbGUgIT0gIjAyd19DT05fMSIsIF0NCg0KIyBBZGQgbGFtYmRhcyB0byBhbGwgdmFsdWVzLCB0aGVuIHRha2UgYSBsb2cNCmRtLmx0cG0gPC0gdChhcHBseShYID0gZG0udHBtLA0KICAgICAgICAgICAgICAgICAgICAgIE1BUkdJTiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oYSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIDwtIG1pbihhW2EgPiAwXSkvMTANCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhhICsgbGFtYmRhKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pKQ0KDQojIFBDQS0tLS0NCm0xIDwtIHByY29tcCh0KGRtLmx0cG0pLA0KICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsDQogICAgICAgICAgICAgc2NhbGUuID0gVFJVRSkNCg0KczEgPC0gc3VtbWFyeShtMSkNCnMxDQpgYGANCg0KIyBQYXJldG8gY2hhcnQgb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IHByaW5jaXBhbCBjb21wb25lbnRzDQpgYGB7ciBwY2FfdmFyX3Bsb3R9DQppbXAgPC0gZGF0YS50YWJsZShQQyA9IGNvbG5hbWVzKHMxJGltcG9ydGFuY2UpLA0KICAgICAgICAgICAgICAgICAgVmFyaWFuY2UgPSAxMDAqczEkaW1wb3J0YW5jZVsyLCBdLA0KICAgICAgICAgICAgICAgICAgQ3VtdWxhdGl2ZSA9IDEwMCpzMSRpbXBvcnRhbmNlWzMsIF0pDQppbXAkUEMgPC0gZmFjdG9yKGltcCRQQywNCiAgICAgICAgICAgICAgICAgbGV2ZWxzID0gaW1wJFBDKQ0KcDEgPC0gZ2dwbG90KGltcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDLA0KICAgICAgICAgICAgICAgICB5ID0gVmFyaWFuY2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLA0KICAgICAgICAgICBmaWxsID0gImdyZXkiLA0KICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcmVzY2FsZShDdW11bGF0aXZlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqMzAvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzMCkpLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gcmVwKDEsIG5yb3coaW1wKSkpKSArDQogIGdlb21fcG9pbnQoYWVzKHkgPSByZXNjYWxlKEN1bXVsYXRpdmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqMzAvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMzApKSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCIlIFZhcmlhbmNlIEV4cGxhaW5lZCIsDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMzAsIGJ5ID0gNSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwYXN0ZShzZXEoMCwgMzAsIGJ5ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiksDQogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKHRyYW5zID0gfi4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBDdW11bGF0aXZlIFZhcmlhbmNlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDMwLCBsZW5ndGgub3V0ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlKHNlcSgwLCAxMDAsIGxlbmd0aC5vdXQgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIikpKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGNhX3BhcmV0by50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcHJpbnQocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHBhaXJ3aXNlDQpgYGB7ciBwY2FfcGxvdHN9DQojIEJpcGxvdCB3aGlsZSBrZWVwIG9ubHkgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyAoSmF2aWVyKS0tLS0NCiMgU2VsZWN0IFBDLXMgdG8gcGxpb3QgKFBDMSAmIFBDMikNCmNob2ljZXMgPC0gYygxOjMpDQoNCiMgU2NvcmVzLCBpLmUuIHBvaW50cyAoZGYudSkNCmR0LnNjciA8LSBkYXRhLnRhYmxlKG0xJHhbLCBjaG9pY2VzXSkNCiMgQWRkIGdyb3VwaW5nIHZhcmlhYmxlcw0KZHQuc2NyJHRydCA8LSBkbWV0YSR0cnQNCmR0LnNjciR0aW1lIDwtIGRtZXRhJHRpbWUNCmR0LnNjciRzYW1wbGUgPC0gZG1ldGEkU2FtcGxlDQoNCiMgTG9hZGluZ3MsIGkuZS4gYXJyb3dzIChkZi52KQ0KZHQucm90IDwtIGFzLmRhdGEuZnJhbWUobTEkcm90YXRpb25bLCBjaG9pY2VzXSkNCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkNCmR0LnJvdCA8LSBkYXRhLnRhYmxlKGR0LnJvdCkNCg0KIyBBeGlzIGxhYmVscw0KdS5heGlzLmxhYnMgPC0gcGFzdGUoY29sbmFtZXMoZHQucm90KVtjaG9pY2VzXSwgDQogICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKm0xJHNkZXZbY2hvaWNlc11eMi9zdW0obTEkc2Rldl4yKSkpDQoNCnAxIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMyLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDEpDQoNCnAyIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDIpDQoNCnAzIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMyLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1syXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDMpDQoNCiMgTGVnZW5kIG9ubHkNCnRtcCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMiwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIlRyZWF0bWVudCIpICsNCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUoIldlZWsiKQ0KcDQgPC0gYXNfZ2dwbG90KGdldF9sZWdlbmQodG1wKSkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGNhLnRpZmYiLA0KICAgICBoZWlnaHQgPSA3LA0KICAgICB3aWR0aCA9IDksDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDQsIA0KICAgICAgICAgICAgIG5yb3cgPSAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIDNEDQpgYGB7ciBwY2FfM2QsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9DQpzY2F0dGVycGxvdDNqcyh4ID0gZHQuc2NyJFBDMSwgDQogICAgICAgICAgICAgICB5ID0gZHQuc2NyJFBDMiwgDQogICAgICAgICAgICAgICB6ID0gZHQuc2NyJFBDMywgDQogICAgICAgICAgICAgICBjb2xvciA9IGFzLm51bWVyaWMoZHQuc2NyJHRydCksDQogICAgICAgICAgICAgICByZW5kZXJlciA9ICJhdXRvIiwNCiAgICAgICAgICAgICAgIHBjaCA9IGR0LnNjciRzYW1wbGUsDQogICAgICAgICAgICAgICBzaXplID0gMC4xKQ0KYGBgDQoNCiMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgKERFU2VxMiBwaXBlbGluZSkNClNvdXJjZXM6ICAgIA0KMS4gW0FuYWx5emluZyBSTkEtc2VxIGRhdGEgd2l0aCBERVNlcTI6SW50ZXJhY3Rpb25zXShodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL0RFU2VxMi9pbnN0L2RvYy9ERVNlcTIuaHRtbCNpbnRlcmFjdGlvbnMpICAgICANCjIuIFtCaW9jb25kdWN0b3IgUXVlc3Rpb246IERFU2VxMiB0aW1lIHNlcmllcyBhbmFseXNpc10oaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC85NzQzMC8pICAgICAgDQpXZSBhcmUgdGVzdGluZyBhIG1vZGVsIHdpdGggdGltZSp0cmVhdG1lbnQgaW50ZXJhY3Rpb24uIFRoZSBpZGVhIGhlcmUgaXMgdG8gZmluZCBnZW5lcyB3aXRoIHNpZ25pZmljYW50IGludGVyYWN0aW9uIHRlcm0uIFRoYXQgd291bGQgc3VnZ2VzdCB0aGF0IHRoZSBnZW5lIGV4cHJlc3Npb25kaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0cmVhdG1lbnRzIGRlcGVuZGVkIG9uIHRpbWUuIFRIZXJlIGFyZSBzZXZlcmFsIHBvc3NpYmxlIHNjZW5hcmlvczogICAgDQphLiBObyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG5lZ2F0aXZlIGNvbnRyb2wgYW5kIHRoZSBwb3NpdGl2ZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gVGhpcyB3aWxsIHNob3cgdGhlIGVmZmVjdCBvZiB0aGUgZGlzZWFzZSAoVVZCIHJhZGlhdGlvbiwgaW4gdGhpcyBjYXNlKS4gICAgIA0KYi4gU2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgbm8gZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gU2FtZSBhcyAoYSkgYWJvdmUuICAgICANCmMuIERpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHBvc2l0aXZlIGNvbnRyb2wgYW5kIHRoZSBTRk4tdHJlYXRlZCBncm91cHMuIEhlcmUsIHdlIGFyZSBpbnRlcmVzdGVkIGluIHRoZSByZXZlcnNhbCBvZiBVVkIgZWZmZWN0LiBBZ2FpbiwgdGhlIGludGVyYWN0aW9uIHRlcm0gd2lsbCBuZWVkIHRvIGJlIHNpZ25pZmljYW50IGZvciB0aGUgcmVhc29ucyBkZXNjcmliZWQgYWJvdmUuICAgICAgDQoNCmBgYHtyIGRlc2VxMn0NCiMgUmVsZXZlbDogbWFrZSBhbGwgY29tcGFyaXNvbnMgd2l0aCB0aGUgcG9zaXRpdmUgY29udHJvbCAoVVZCKQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KDQpkdG08LSBhcy5tYXRyaXgoZHQxWywgZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICB3aXRoID0gRkFMU0VdKQ0Kcm93bmFtZXMoZHRtKSA8LSBkdDEkR2VuZWlkDQoNCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGR0bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gZG1ldGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCkNCiMgSWYgYWxsIHNhbXBsZXMgY29udGFpbiB6ZXJvcywgZ2VvbWV0cmljIG1lYW5zIGNhbm5vdCBiZQ0KIyBlc3RpbWF0ZWQuIENoYW5nZSBkZWZhdWx0ICd0eXBlID0gInJhdGlvIicgdG8gJ3R5cGUgPSAicG9zY291bnRzIicuDQojIFR5cGUgJz9ERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMnIGZvciBtb3JlIGRldGFpbHMuDQpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhvYmplY3QgPSBkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBvc2NvdW50cyIpDQoNCiMgUnVuIERFU2VxLS0tLQ0KZGRzIDwtIERFU2VxKG9iamVjdCA9IGRkcywNCiAgICAgICAgICAgICAjIHRlc3QgPSAiTFJUIiwNCiAgICAgICAgICAgICAjIHJlZHVjZWQgPSB+IHRpbWUgKyB0cnQsDQogICAgICAgICAgICAgZml0VHlwZSA9ICJsb2NhbCIsDQogICAgICAgICAgICAgc2ZUeXBlID0gInJhdGlvIiwNCiAgICAgICAgICAgICBwYXJhbGxlbCA9IEZBTFNFKQ0KDQojIE5PVEUgKGZyb20gREVTZXEgaGVscCBmaWxlLCBzZWN0aW9uIFZhbHVlKToNCiMgQSBERVNlcURhdGFTZXQgb2JqZWN0IHdpdGggcmVzdWx0cyBzdG9yZWQgYXMgbWV0YWRhdGEgY29sdW1ucy4gDQojIFRoZXNlIHJlc3VsdHMgc2hvdWxkIGFjY2Vzc2VkIGJ5IGNhbGxpbmcgdGhlIHJlc3VsdHMgZnVuY3Rpb24uIA0KIyBCeSBkZWZhdWx0IHRoaXMgd2lsbCByZXR1cm4gdGhlIGxvZzIgZm9sZCBjaGFuZ2VzIGFuZCBwLXZhbHVlcw0KIyBmb3IgdGhlIGxhc3QgdmFyaWFibGUgaW4gdGhlIGRlc2lnbiBmb3JtdWxhLiANCiMgU2VlIHJlc3VsdHMgZm9yIGhvdyB0byBhY2Nlc3MgcmVzdWx0cyBmb3Igb3RoZXIgdmFyaWFibGVzLg0KIyBJbiB0aGlzIGNhc2UsIHRoZSBsYXN0IHRlcm0gaXMgdGhlIGludGVyYWN0aW9uIHRlcm0gdHJ0OnRpbWUNCg0KIyBOT1RFOiANCiMgTGlrZWxpaG9vZCByYXRpbyB0ZXN0IChMUlQpIChjaGktc3F1YXJlZCB0ZXN0KSBmb3IgR0xNIHdpbGwgb25seSByZXR1cm4gDQojIHRoZSByZXN1bHRzIGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBmdWxsIGFuZCB0aGUgcmVkdWNlZCBtb2RlbA0KDQpyZXN1bHRzTmFtZXMoZGRzKQ0KDQojIE1vZGVsIG1hdHJpeA0KbW0xIDwtIG1vZGVsLm1hdHJpeCh+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCwgZG1ldGEpDQptbTENCmBgYA0KDQojIFJlc3VsdHMNCiMjIEVmZmVjdCBvZiBVVkIgYXQgV2VlayAyDQpgYGB7ciBkZXNlcTJfcmVzdWx0c193ZWVrMl9jb25fdXZifQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygwLDAsMCwxLDAsMCwwLDAsMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzX2Nvbl91dmJfd2VlazJbb3JkZXIocmVzX2Nvbl91dmJfd2VlazIkcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0Kc3VtbWFyeShyZXNfY29uX3V2Yl93ZWVrMikNCg0KIyBIb3cgbWFueSBhZGp1c3RlZCBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjA1Pw0Kc3VtKHJlc19jb25fdXZiX3dlZWsyJHBhZGogPCAwLjEsIA0KICAgIG5hLnJtID0gVFJVRSkNCg0KIyBNQSBwbG90DQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93Ml9jb25fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90TUEocmVzX2Nvbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJDb250cm9sIHZzLiBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkNCmdyYXBoaWNzLm9mZigpDQoNCnBsb3RNQShyZXNfY29uX3V2Yl93ZWVrMiwNCiAgICAgICAgICAgICBtYWluID0gIkNvbnRyb2wgdnMuIFVWQiBhdCBXZWVrIDIiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KQ0KYGBgDQoNCiMjIFByb3RlY3RpdmUgZWZmZWN0IG9mIFNGTiBhdCBXZWVrIDINCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsyX3Nmbl91dmJ9DQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXN1bHRzKGRkcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKDAsMCwwLDAsMSwwLDAsMCwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXNfc2ZuX3V2Yl93ZWVrMltvcmRlcihyZXNfc2ZuX3V2Yl93ZWVrMiRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpzdW1tYXJ5KHJlc19zZm5fdXZiX3dlZWsyKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX3Nmbl91dmJfd2VlazIkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL21hX3cyX3Nmbl91dmIudGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gNywNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHBsb3RNQShyZXNfc2ZuX3V2Yl93ZWVrMiwNCiAgICAgICAgICAgICBtYWluID0gIlVWQitTRk4gdnMgVVZCIGF0IFdlZWsgMiIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocGxvdE1BKHJlc19zZm5fdXZiX3dlZWsyLA0KICAgICAgICAgICAgIG1haW4gPSAiVVZCK1NGTiB2cyBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkpDQpgYGANCg0KIyMgR2VuZXMgdGhhdCB3ZXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWF0ZWQgYXQgYm90aCBjb21wYXJpc29ucyBhdCBXZWVrIDINCmBgYHtyIHNpZ25fdzJ9DQpsZ2VuZS53Mi5jb24gPC0gdW5pcXVlKHJlc19jb25fdXZiX3dlZWsyQHJvd25hbWVzW3Jlc19jb25fdXZiX3dlZWsyJHBhZGogPCAwLjFdKQ0KbGdlbmUudzIuc2ZuIDwtIHVuaXF1ZShyZXNfc2ZuX3V2Yl93ZWVrMkByb3duYW1lc1tyZXNfc2ZuX3V2Yl93ZWVrMiRwYWRqIDwgMC4xXSkNCmxnZW5lLncyIDwtIGxnZW5lLncyLmNvbltsZ2VuZS53Mi5jb24gJWluJSBsZ2VuZS53Mi5zZm5dDQpsZ2VuZS53MiA8LSBsZ2VuZS53MiBbIWlzLm5hKGxnZW5lLncyICldDQpsZ2VuZS53Mg0KYGBgDQoNClBsb3Qgb2YgREVTZXEtbm9ybWFsaXplZGNvdW50cyBvZiBnZW5lcyBzaWduaWZpY2FudCBpbiBib3RoIGNvbXBhcmlzb25zIGF0IFdlZWsgMjogICANCg0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm19DQojIEdldCB0aGUgREVTZXEtbm9ybWFsaXplIGNvdW50cw0KZHAxIDwtIGxpc3QoKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGxnZW5lLncyKSkgew0KICBvdXQgPC0gcGxvdENvdW50cyhkZHMsIA0KICAgICAgICAgICAgICAgICAgICBnZW5lID0gbGdlbmUudzJbW2ldXSwNCiAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSBjKCJ0cnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRpbWUiKSwNCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFRSVUUpDQogIGRwMVtbaV1dIDwtIGRhdGEudGFibGUoR2VuZWlkID0gbGdlbmUudzJbW2ldXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBTYW1wbGUgPSByb3duYW1lcyhvdXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG91dCkNCn0NCmRwMSA8LSByYmluZGxpc3QoZHAxKQ0KZHAxJHRydCA8LSBmYWN0b3IoZHAxJHRydCwNCiAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQpkcDEkdGltZSA8LSBmYWN0b3IoZHAxJHRpbWUsDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldlZWsgMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAyNSIpKQ0KZHAxJEdlbmVpZCA8LSBmYWN0b3IoZHAxJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lLncyKQ0KZHAxWywgbXUgOj0gbWVhbihjb3VudCwNCiAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwNCiAgICBieSA9IGMoIkdlbmVpZCIsDQogICAgICAgICAgICJ0cnQiLA0KICAgICAgICAgICAidGltZSIpXQ0KZG11IDwtIHVuaXF1ZShkcDFbLCAtYygiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImNvdW50IildKQ0KaGVhZChkbXUpDQpgYGANCg0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm1fdzJfdXBfZG4sIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCmRtdS53MiA8LSBkbXVbdGltZSA9PSAiV2VlayAyIiwgXQ0KZG11LncyWywgdXAuZG4gOj0gKG11W3RydCA9PSAiVVZCIl0gPiBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA+IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDEgPC0gZ2dwbG90KGRtdS53Mlt1cC5kbiA9PSBUUlVFLCBdLA0KICAgICAgICAgICAgIGFlcyh4ID0gdHJ0LA0KICAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICAgICAgICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgICAgICAgZ2VvbV9saW5lKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKw0KICAgICAgICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICAgICAgICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogICAgICAgIHNjYWxlX3lfY29udGludW91cygiRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIGF0IFdlZWsgMiIpICsNCiAgICAgICAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikgKw0KICAgICAgICBnZ3RpdGxlKCJHZW5lcyBVcHJlZ3VsYXRlZCBieSBVVkIiKQ0KdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpDQoNCnRpZmYoZmlsZW5hbWUgPSAidG1wL3cyX3VwX2RuLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gMzAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCiMjIERpZCBkb3duLXVwLWRvd24gdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3Bsb3RfYWxsX3VwX2RuLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEyfQ0KZHAxLnRtcCA8LSBkcDFbZHAxJEdlbmVpZCAlaW4lIHVuaXF1ZShkbXUudzIkR2VuZWlkW2RtdS53MiR1cC5kbl0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJHVwLmRuXSksIF0NCnAxIDwtIGdncGxvdChkcDEudG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICAgeSA9IGNvdW50LA0KICAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgc2l6ZSA9IDUsDQogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fbGluZShkYXRhID0gZG11LnRtcCwNCiAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSB0cnQsDQogICAgICAgICAgICAgICAgY29sb3VyID0gdHJ0KSwNCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgIGFscGhhID0gMC41LA0KICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkRFU2VxLU5vcm1hbGl6ZWQgQ291bnRzIikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKQ0KcHJpbnQocDEpDQpgYGANCg0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm1fdzJfZG5fdXAsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCmRtdS53MlssIGRuLnVwIDo9IChtdVt0cnQgPT0gIlVWQiJdIDwgbXVbdHJ0ID09ICJDT04iXSkgJg0KICAgICAgICAgICAgICAgKG11W3RydCA9PSAiVVZCIl0gPCBtdVt0cnQgPT0gIlNGTiJdKSwNCiAgICAgICBieSA9IEdlbmVpZF0NCnAyIDwtIGdncGxvdChkbXUudzJbZG4udXAgPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDIiKSArDQogICAgICAgIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpICsNCiAgICAgICAgZ2d0aXRsZSgiR2VuZXMgRG93bnJlZ3VsYXRlZCBieSBVVkIiKQ0KdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpDQoNCnRpZmYoZmlsZW5hbWUgPSAidG1wL3cyX2RuX3VwLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwMikNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAyKQ0KYGBgDQoNCiMjIERpZCB1cC1kb3duLXVwIHRyZW5kIHBlcnNpc3Q/DQpgYGB7ciBkZXNlcTJfdzJzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF9kbl91cCwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncyJEdlbmVpZFtkbXUudzIkZG4udXBdKSwgXQ0KZG11LnRtcCA8LSBkbXVbZG11JEdlbmVpZCAlaW4lIHVuaXF1ZShkbXUudzIkR2VuZWlkW2RtdS53MiRkbi51cF0pLCBdDQpwMSA8LSBnZ3Bsb3QoZHAxLnRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgIHkgPSBjb3VudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0cnQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSB0cnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV95IikgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIHNpemUgPSA1LA0KICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRtdS50bXAsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQoNCkluIG1hbnkgb2YgdGhlc2UgZ2VuZXMsIFVWQitTRk4gbW92ZWQgY2xvc2VyIHRvIFVWQiBvdmVyIHRpbWUuDQoNCiMjIEhlYXRtYXAgZm9yIFdlZWsgMiBkaWZmZXJlbnRpYWxseSBtZXRoeWxhdGVkIGdlbmVzDQpgYGB7ciB3Ml9oZWF0bWFwLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KdXAuZG4udzIgPC0gdW5pcXVlKGFzLmNoYXJhY3RlcihkbXUudzIkR2VuZWlkW2RtdS53MiR1cC5kbl0pKQ0KZG4udXAudzIgPC0gdW5pcXVlKGFzLmNoYXJhY3RlcihkbXUudzIkR2VuZWlkW2RtdS53MiRkbi51cF0pKQ0KbGwgPC0gdW5pcXVlKGModXAuZG4udzIsDQogICAgICAgICAgICAgICBkbi51cC53MikpDQojIDM2IGdlbmVzDQoNCmNvbl91dmJfd2VlazIgPC0gZGF0YS50YWJsZShHZW5laWQgPSByZXNfY29uX3V2Yl93ZWVrMkByb3duYW1lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyRm9sZENoYW5nZSA9IHJlc19jb25fdXZiX3dlZWsyQGxpc3REYXRhJGxvZzJGb2xkQ2hhbmdlKQ0KDQpzZm5fdXZiX3dlZWsyIDwtIGRhdGEudGFibGUoR2VuZWlkID0gcmVzX3Nmbl91dmJfd2VlazJAcm93bmFtZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMkZvbGRDaGFuZ2UgPSAtcmVzX3Nmbl91dmJfd2VlazJAbGlzdERhdGEkbG9nMkZvbGRDaGFuZ2UpDQoNCnQxIDwtIG1lcmdlKGNvbl91dmJfd2VlazJbY29uX3V2Yl93ZWVrMiRHZW5laWQgJWluJSBsbCwgXSwNCiAgICAgICAgICAgIHNmbl91dmJfd2VlazJbc2ZuX3V2Yl93ZWVrMiRHZW5laWQgJWluJSBsbCwgXSwNCiAgICAgICAgICAgIGJ5ID0gIkdlbmVpZCIpDQpjb2xuYW1lcyh0MSlbMjozXSA8LSBjKCJDb250cm9sIHZzLiBVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAiVVZCIHZzLiBTRk4rVVZCIikNCnQxIDwtIHQxW29yZGVyKHQxJGBDb250cm9sIHZzLiBVVkJgLA0KICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFRSVUUpLCBdDQp3cml0ZS5jc3YodDEsDQogICAgICAgICAgZmlsZSA9ICJ0bXAvdzJfc2lnbl9jaGFuZ2VzLmNzdiIsDQogICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpDQoNCmxsIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdDEsDQogICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMjozLA0KICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiQ29tcGFyaXNvbiIsDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJHZW5lIEV4cHJlc3Npb24gRGlmZiIpDQpsbCRDb21wYXJpc29uIDwtIGZhY3RvcihsbCRDb21wYXJpc29uLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ29udHJvbCB2cy4gVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiB2cy4gU0ZOK1VWQiIpKQ0KbHZscyA8LSBsbFtsbCRDb21wYXJpc29uID09ICJDb250cm9sIHZzLiBVVkIiLCBdDQpsbCRHZW5laWQgPC0gZmFjdG9yKGxsJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbHZscyRHZW5laWRbb3JkZXIobHZscyRgR2VuZSBFeHByZXNzaW9uIERpZmZgKV0pDQoNCiMgQWRkIGRlbmRyb2dyYW0tLS0tDQpkdC5kbmRyIDwtIGRhdGEuZnJhbWUodDFbR2VuZWlkICVpbiUgbGV2ZWxzKGxsJEdlbmVpZCksIF0pDQpyb3duYW1lcyhkdC5kbmRyKSA8LSBkdC5kbmRyJEdlbmUNCmR0LmRuZHIgPC0gZHQuZG5kclssIC0xXQ0KDQojIENvbXB1dGUgZGlzdGFuY2VzIGJldHdlZW4gZ2VuZXMtLS0tDQpzYW1wbGVEaXN0cyA8LSBkaXN0KGR0LmRuZHIpDQoNCiMgTWFrZSBkZW5kcm9ncmFtIGRhdGEtLS0tDQpkaGMgPC0gYXMuZGVuZHJvZ3JhbShoY2x1c3QoZCA9IHNhbXBsZURpc3RzKSwNCiAgICAgICAgICAgICAgICAgICAgIGhvcml6ID0gVFJVRSkNCmRkYXRhIDwtIGRlbmRyb19kYXRhKGRoYywgDQogICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlY3RhbmdsZSIpDQoNCiMgU2VnbWVudCBkYXRhLS0tLQ0KZHRwMSA8LSBzZWdtZW50KGRkYXRhKQ0KDQojIEhpdG1hcCBkYXRhLS0tLQ0KZHRwMiA8LSBsbA0KZHRwMiRHZW5laWQgPC0gZmFjdG9yKGR0cDIkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGRkYXRhJGxhYmVscyRsYWJlbCkNCg0Kb2Zmc2V0LnNpemUgPC0gNA0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0cDIpICsNCiAgY29vcmRfcG9sYXIoInkiLA0KICAgICAgICAgICAgICBzdGFydCA9IC0wLjMsDQogICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fdGlsZShhZXMoeCA9ICBhcy5udW1lcmljKENvbXBhcmlzb24pLA0KICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsIA0KICAgICAgICAgICAgICAgIGZpbGwgPSBgR2VuZSBFeHByZXNzaW9uIERpZmZgKSwNCiAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGR0cDJbQ29tcGFyaXNvbiA9PSAiQ29udHJvbCB2cy4gVVZCIiwgXSwNCiAgICAgICAgICAgIGFlcyh4ID0gcmVwKDEuNzUsDQogICAgICAgICAgICAgICAgICAgICAgICBubGV2ZWxzKEdlbmVpZCkpLA0KICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgYW5nbGUgPSA5MCArIHNlcShmcm9tID0gMzAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IDMzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSBubGV2ZWxzKEdlbmVpZCkpW2FzLm51bWVyaWMoR2VuZWlkKV0gKyANCiAgICAgICAgICAgICAgICAgIG9mZnNldC5zaXplLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gdW5pcXVlKEdlbmVpZCkpLA0KICAgICAgICAgICAgaGp1c3QgPSAwKSArDQogIGdlb21fdGV4dChkYXRhID0gZHRwMltHZW5laWQgPT0gbGV2ZWxzKGR0cDIkR2VuZWlkKVsxXSwgXSwNCiAgICAgICAgICAgIGFlcyh4ID0gMTpubGV2ZWxzKENvbXBhcmlzb24pLA0KICAgICAgICAgICAgICAgIHkgPSByZXAoLW9mZnNldC5zaXplLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmxldmVscyhDb21wYXJpc29uKSksDQogICAgICAgICAgICAgICAgYW5nbGUgPSAwLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gbGV2ZWxzKENvbXBhcmlzb24pKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMSwNCiAgICAgICAgICAgIHNpemUgPSA1KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJyZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJncmVlbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAiZ3JleSIsIA0KICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZSgiIiwNCiAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBjKDAsIDApKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsDQogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsICJpbiIpLA0KICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC4zLCAiaW4iKSkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGR0cDEsDQogICAgICAgICAgICAgICBhZXMoeCA9IC1zcXJ0KHkpICsgMC41LA0KICAgICAgICAgICAgICAgICAgIHkgPSB4LCANCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gLXNxcnQoeWVuZCkgKyAwLjUsDQogICAgICAgICAgICAgICAgICAgeWVuZCA9IHhlbmQpLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpIA0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC9za2luX3Vidl93Ml9zZm5faGl0bWFwX3dpdGhfcGh5bG8udGlmZiIsDQogICAgIGhlaWdodCA9IDgsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnBsb3QocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIyBWZW5uIERpYWdyYW0sIFdlZWsgMg0KYGBge3IgdzItdmVubiwgZmlnLmhlaWdodD02LGZpZy53aWR0aD00fQ0KIyAxLiBDdHJsIHZzLiBVVkINCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAxNTQ2LCA5JQ0KIyBMRkMgPCAwIChkb3duKSAgICAgOiAxNTM3LCA4LjklDQojIDIzIGdlbmVzIGRvd24tdXAtZG93bg0KDQojIDIuIFNGTitVVkIgdnMuIFVWQg0KIyBhZGp1c3RlZCBwLXZhbHVlIDwgMC4xDQojIExGQyA+IDAgKHVwKSAgICAgICA6IDI2LCAwLjE1JQ0KIyBMRkMgPCAwIChkb3duKSAgICAgOiAzNSwgMC4yJQ0KIyAxMyBnZW5zIHVwLWRvd24tdXANCg0KcDEgPC0gZ2dwbG90KCkgKw0KICBnZW9tX2NpcmNsZShhZXMoeDAgPSBjKDEsIDIsIDEsIDIpLA0KICAgICAgICAgICAgICAgICAgeTAgPSBjKDEsIDEsIDQsIDQpLA0KICAgICAgICAgICAgICAgICAgciA9IHJlcCgxLCA0KSwNCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmFjdG9yKGMoMiwgMSwgMSwgMikpKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gcmVwKGMoMC41LCAxLjUsIDIuNSksIDIpLA0KICAgICAgICAgICAgICAgIHkgPSByZXAoYygxLCA0KSwgZWFjaCA9IDMpLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KGMoMjYsIDEzLCAzNSwgMTU0NiwgMjMsIDE1MzcpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiwiKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyZWVuIiwgInJlZCIpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2tpbl91YnZfc2ZuX3cyX3Zlbm4udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gNCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnBsb3QocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIyBFZmZlY3Qgb2YgVVZCIGF0IFdlZWsgMTUNCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsxNV9jb25fdXZifQ0KcmVzX2Nvbl91dmJfd2VlazE1IDwtIHJlc3VsdHMoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoMCwxLDAsMSwwLDAsMCwwLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkNCnJlc19jb25fdXZiX3dlZWsxNSA8LSByZXNfY29uX3V2Yl93ZWVrMTVbb3JkZXIocmVzX2Nvbl91dmJfd2VlazE1JHBhZGosDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX2Nvbl91dmJfd2VlazE1KQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMT8NCnN1bShyZXNfY29uX3V2Yl93ZWVrMTUkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL21hX3cxNV9jb25fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90TUEocmVzX2Nvbl91dmJfd2VlazE1LA0KICAgICAgICAgICAgIG1haW4gPSAiQ29udHJvbCB2cy4gVVZCIGF0IFdlZWsgMTUiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcGxvdE1BKHJlc19jb25fdXZiX3dlZWsxNSwNCiAgICAgICAgICAgICBtYWluID0gIkNvbnRyb2wgdnMuIFVWQiBhdCBXZWVrIDE1IiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkNCmBgYA0KIyMgUHJvdGVjdGl2ZSBlZmZlY3Qgb2YgU0ZOIGF0IFdlZWsgMTUNCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsxNV9zZm5fdXZifQ0KcmVzX3Nmbl91dmJfd2VlazE1IDwtIHJlc3VsdHMoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoMCwxLDAsMCwxLDAsMCwwLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkNCnJlc19zZm5fdXZiX3dlZWsxNSA8LSByZXNfc2ZuX3V2Yl93ZWVrMTVbb3JkZXIocmVzX3Nmbl91dmJfd2VlazE1JHBhZGosDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX3Nmbl91dmJfd2VlazE1KQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX3Nmbl91dmJfd2VlazE1JHBhZGogPCAwLjEsIA0KICAgIG5hLnJtID0gVFJVRSkNCg0KIyBNQSBwbG90DQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93Ml9zZm5fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwbG90TUEocmVzX3Nmbl91dmJfd2VlazE1LA0KICAgICAgICAgICAgIG1haW4gPSAiVVZCK1NGTiB2cyBVVkIgYXQgV2VlayAxNSIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocGxvdE1BKHJlc19zZm5fdXZiX3dlZWsxNSwNCiAgICAgICAgICAgICBtYWluID0gIlVWQitTRk4gdnMgVVZCIGF0IFdlZWsgMTUiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KSkNCmBgYA0KDQojIyBHZW5lcyB0aGF0IHdlcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYXRlZCBhdCBib3RoIGNvbXBhcmlzb25zIGF0IFdlZWsgMTUNCmBgYHtyIHNpZ25fdzE1fQ0KbGdlbmUudzE1LmNvbiA8LSB1bmlxdWUocmVzX2Nvbl91dmJfd2VlazE1QHJvd25hbWVzW3Jlc19jb25fdXZiX3dlZWsxNSRwYWRqIDwgMC4xXSkNCmxnZW5lLncxNS5zZm4gPC0gdW5pcXVlKHJlc19zZm5fdXZiX3dlZWsxNUByb3duYW1lc1tyZXNfc2ZuX3V2Yl93ZWVrMTUkcGFkaiA8IDAuMV0pDQpsZ2VuZS53MTUgPC0gbGdlbmUudzE1LmNvbltsZ2VuZS53MTUuY29uICVpbiUgbGdlbmUudzE1LnNmbl0NCmxnZW5lLncxNSA8LSBsZ2VuZS53MTUgWyFpcy5uYShsZ2VuZS53MTUgKV0NCmxnZW5lLncxNQ0KYGBgDQpQbG90IG9mIERFU2VxLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgc2lnbmlmaWNhbnQgaW4gYm90aCBjb21wYXJpc29ucyBhdCBXZWVrIDE1OiAgIA0KDQpgYGB7ciBkZXNlcTJfdzE1c2lnbl9kZXNlcW5vcm19DQojIEdldCB0aGUgREVTZXEtbm9ybWFsaXplIGNvdW50cw0KZHAxIDwtIGxpc3QoKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGxnZW5lLncxNSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lLncxNVtbaV1dLA0KICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9IGMoInRydCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGltZSIpLA0KICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVFJVRSkNCiAgZHAxW1tpXV0gPC0gZGF0YS50YWJsZShHZW5laWQgPSBsZ2VuZS53MTVbW2ldXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBTYW1wbGUgPSByb3duYW1lcyhvdXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG91dCkNCn0NCmRwMSA8LSByYmluZGxpc3QoZHAxKQ0KZHAxJHRydCA8LSBmYWN0b3IoZHAxJHRydCwNCiAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQpkcDEkdGltZSA8LSBmYWN0b3IoZHAxJHRpbWUsDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldlZWsgMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAyNSIpKQ0KZHAxJEdlbmVpZCA8LSBmYWN0b3IoZHAxJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lLncxNSkNCmRwMVssIG11IDo9IG1lYW4oY291bnQsDQogICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgYnkgPSBjKCJHZW5laWQiLA0KICAgICAgICAgICAidHJ0IiwNCiAgICAgICAgICAgInRpbWUiKV0NCmRtdSA8LSB1bmlxdWUoZHAxWywgLWMoIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICJjb3VudCIpXSkNCmhlYWQoZG11KQ0KYGBgDQoNCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV93MTVfdXBfZG4sIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCmRtdS53MTUgPC0gZG11W3RpbWUgPT0gIldlZWsgMTUiLCBdDQpkbXUudzE1WywgdXAuZG4gOj0gKG11W3RydCA9PSAiVVZCIl0gPiBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA+IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDEgPC0gZ2dwbG90KGRtdS53MTVbdXAuZG4gPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDE1IikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIFVwcmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvdzE1X3VwX2RuLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gMzAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCiMjIERpZCBkb3duLXVwLWRvd24gdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF91cF9kbiwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncxNSRHZW5laWRbZG11LncxNSR1cC5kbl0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MTUkR2VuZWlkW2RtdS53MTUkdXAuZG5dKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQpgYGB7ciBkZXNlcTJfdzE1c2lnbl9kZXNlcW5vcm1fdzE1X2RuX3VwLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9DQpkbXUudzE1WywgZG4udXAgOj0gKG11W3RydCA9PSAiVVZCIl0gPCBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA8IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDIgPC0gZ2dwbG90KGRtdS53MTVbZG4udXAgPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDE1IikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIERvd25yZWd1bGF0ZWQgYnkgVVZCIikNCnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC93MTVfZG5fdXAudGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDIpDQpgYGANCg0KIyMgRGlkIHVwLWRvd24tdXAgdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF9kbl91cCwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncxNSRHZW5laWRbZG11LncxNSRkbi51cF0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MTUkR2VuZWlkW2RtdS53MTUkZG4udXBdKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQojIyBIZWF0bWFwIGZvciBXZWVrIDE1IGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgZ2VuZXMNCmBgYHtyIHcxNV9oZWF0bWFwLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KdXAuZG4udzE1IDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncxNSRHZW5laWRbZG11LncxNSR1cC5kbl0pKQ0KZG4udXAudzE1IDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncxNSRHZW5laWRbZG11LncxNSRkbi51cF0pKQ0KbGwgPC0gdW5pcXVlKGModXAuZG4udzE1LA0KICAgICAgICAgICAgICAgZG4udXAudzE1KSkNCiMgMTYgZ2VuZXMNCg0KY29uX3V2Yl93ZWVrMTUgPC0gZGF0YS50YWJsZShHZW5laWQgPSByZXNfY29uX3V2Yl93ZWVrMTVAcm93bmFtZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMkZvbGRDaGFuZ2UgPSByZXNfY29uX3V2Yl93ZWVrMTVAbGlzdERhdGEkbG9nMkZvbGRDaGFuZ2UpDQoNCnNmbl91dmJfd2VlazE1IDwtIGRhdGEudGFibGUoR2VuZWlkID0gcmVzX3Nmbl91dmJfd2VlazE1QHJvd25hbWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZzJGb2xkQ2hhbmdlID0gLXJlc19zZm5fdXZiX3dlZWsxNUBsaXN0RGF0YSRsb2cyRm9sZENoYW5nZSkNCg0KdDEgPC0gbWVyZ2UoY29uX3V2Yl93ZWVrMTVbY29uX3V2Yl93ZWVrMTUkR2VuZWlkICVpbiUgbGwsIF0sDQogICAgICAgICAgICBzZm5fdXZiX3dlZWsxNVtzZm5fdXZiX3dlZWsxNSRHZW5laWQgJWluJSBsbCwgXSwNCiAgICAgICAgICAgIGJ5ID0gIkdlbmVpZCIpDQpjb2xuYW1lcyh0MSlbMjozXSA8LSBjKCJDb250cm9sIHZzLiBVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAiVVZCIHZzLiBTRk4rVVZCIikNCnQxIDwtIHQxW29yZGVyKHQxJGBDb250cm9sIHZzLiBVVkJgLA0KICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFRSVUUpLCBdDQp3cml0ZS5jc3YodDEsDQogICAgICAgICAgZmlsZSA9ICJ0bXAvdzE1X3NpZ25fY2hhbmdlcy5jc3YiLA0KICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQpsbCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHQxLA0KICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDI6MywNCiAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIkNvbXBhcmlzb24iLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiR2VuZSBFeHByZXNzaW9uIERpZmYiKQ0KbGwkQ29tcGFyaXNvbiA8LSBmYWN0b3IobGwkQ29tcGFyaXNvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNvbnRyb2wgdnMuIFVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIgdnMuIFNGTitVVkIiKSkNCmx2bHMgPC0gbGxbbGwkQ29tcGFyaXNvbiA9PSAiQ29udHJvbCB2cy4gVVZCIiwgXQ0KbGwkR2VuZWlkIDwtIGZhY3RvcihsbCRHZW5laWQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGx2bHMkR2VuZWlkW29yZGVyKGx2bHMkYEdlbmUgRXhwcmVzc2lvbiBEaWZmYCldKQ0KDQojIEFkZCBkZW5kcm9ncmFtLS0tLQ0KZHQuZG5kciA8LSBkYXRhLmZyYW1lKHQxW0dlbmVpZCAlaW4lIGxldmVscyhsbCRHZW5laWQpLCBdKQ0Kcm93bmFtZXMoZHQuZG5kcikgPC0gZHQuZG5kciRHZW5lDQpkdC5kbmRyIDwtIGR0LmRuZHJbLCAtMV0NCg0KIyBDb21wdXRlIGRpc3RhbmNlcyBiZXR3ZWVuIGdlbmVzLS0tLQ0Kc2FtcGxlRGlzdHMgPC0gZGlzdChkdC5kbmRyKQ0KDQojIE1ha2UgZGVuZHJvZ3JhbSBkYXRhLS0tLQ0KZGhjIDwtIGFzLmRlbmRyb2dyYW0oaGNsdXN0KGQgPSBzYW1wbGVEaXN0cyksDQogICAgICAgICAgICAgICAgICAgICBob3JpeiA9IFRSVUUpDQpkZGF0YSA8LSBkZW5kcm9fZGF0YShkaGMsIA0KICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZWN0YW5nbGUiKQ0KDQojIFNlZ21lbnQgZGF0YS0tLS0NCmR0cDEgPC0gc2VnbWVudChkZGF0YSkNCg0KIyBIaXRtYXAgZGF0YS0tLS0NCmR0cDIgPC0gbGwNCmR0cDIkR2VuZWlkIDwtIGZhY3RvcihkdHAyJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBkZGF0YSRsYWJlbHMkbGFiZWwpDQoNCm9mZnNldC5zaXplIDwtIDQNCg0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkdHAyKSArDQogIGNvb3JkX3BvbGFyKCJ5IiwNCiAgICAgICAgICAgICAgc3RhcnQgPSAtMC4zLA0KICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAtMSkgKw0KICBnZW9tX3RpbGUoYWVzKHggPSAgYXMubnVtZXJpYyhDb21wYXJpc29uKSwNCiAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLCANCiAgICAgICAgICAgICAgICBmaWxsID0gYEdlbmUgRXhwcmVzc2lvbiBEaWZmYCksDQogICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBkdHAyW0NvbXBhcmlzb24gPT0gIkNvbnRyb2wgdnMuIFVWQiIsIF0sDQogICAgICAgICAgICBhZXMoeCA9IHJlcCgxLjc1LA0KICAgICAgICAgICAgICAgICAgICAgICAgbmxldmVscyhHZW5laWQpKSwNCiAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgIGFuZ2xlID0gOTAgKyBzZXEoZnJvbSA9IDMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSAzMzAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gbmxldmVscyhHZW5laWQpKVthcy5udW1lcmljKEdlbmVpZCldICsgDQogICAgICAgICAgICAgICAgICBvZmZzZXQuc2l6ZSwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IHVuaXF1ZShHZW5laWQpKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMCkgKw0KICBnZW9tX3RleHQoZGF0YSA9IGR0cDJbR2VuZWlkID09IGxldmVscyhkdHAyJEdlbmVpZClbMV0sIF0sDQogICAgICAgICAgICBhZXMoeCA9IDE6bmxldmVscyhDb21wYXJpc29uKSwNCiAgICAgICAgICAgICAgICB5ID0gcmVwKC1vZmZzZXQuc2l6ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5sZXZlbHMoQ29tcGFyaXNvbikpLA0KICAgICAgICAgICAgICAgIGFuZ2xlID0gMCwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IGxldmVscyhDb21wYXJpc29uKSksDQogICAgICAgICAgICBoanVzdCA9IDEsDQogICAgICAgICAgICBzaXplID0gNSkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAicmVkIiwgDQogICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZ3JlZW4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWlkID0gImdyZXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwLCANCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIiKSArDQogIHNjYWxlX3lfZGlzY3JldGUoIiIsDQogICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLCAwKSkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLA0KICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCAiaW4iKSwNCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMywgImluIikpICsNCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBkdHAxLA0KICAgICAgICAgICAgICAgYWVzKHggPSAtc3FydCh5KSArIDAuNSwNCiAgICAgICAgICAgICAgICAgICB5ID0geCwgDQogICAgICAgICAgICAgICAgICAgeGVuZCA9IC1zcXJ0KHllbmQpICsgMC41LA0KICAgICAgICAgICAgICAgICAgIHllbmQgPSB4ZW5kKSwNCiAgICAgICAgICAgICAgIHNpemUgPSAxKSANCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2tpbl91YnZfdzE1X3Nmbl9oaXRtYXBfd2l0aF9waHlsby50aWZmIiwNCiAgICAgaGVpZ2h0ID0gOCwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCg0KIyMgVmVubiBEaWFncmFtLCBXZWVrIDE1DQpgYGB7ciB3MTUtdmVubiwgZmlnLmhlaWdodD02LGZpZy53aWR0aD00fQ0KIyAxLiBDdHJsIHZzLiBVVkINCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAxNDQ5LCA4LjQlDQojIExGQyA8IDAgKGRvd24pICAgICA6IDE0ODEsIDguNiUNCiMgMjMgZ2VuZXMgZG93bi11cC1kb3duDQoNCiMgMi4gU0ZOK1VWQiB2cy4gVVZCDQojIGFkanVzdGVkIHAtdmFsdWUgPCAwLjENCiMgTEZDID4gMCAodXApICAgICAgIDogMjcsIDAuMTYlDQojIExGQyA8IDAgKGRvd24pICAgICA6IDksIDAuMDUyJQ0KIyAxMyBnZW5zIHVwLWRvd24tdXANCg0KcDEgPC0gZ2dwbG90KCkgKw0KICBnZW9tX2NpcmNsZShhZXMoeDAgPSBjKDEsIDIsIDEsIDIpLA0KICAgICAgICAgICAgICAgICAgeTAgPSBjKDEsIDEsIDQsIDQpLA0KICAgICAgICAgICAgICAgICAgciA9IHJlcCgxLCA0KSwNCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmFjdG9yKGMoMiwgMSwgMSwgMikpKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gcmVwKGMoMC41LCAxLjUsIDIuNSksIDIpLA0KICAgICAgICAgICAgICAgIHkgPSByZXAoYygxLCA0KSwgZWFjaCA9IDMpLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KGMoMjcsIDgsIDksIDE0NDksIDgsIDE0ODEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiwiKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyZWVuIiwgInJlZCIpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2tpbl91YnZfc2ZuX3cyX3Zlbm4udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gNCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnBsb3QocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIyBJbnRlcmFjdGlvbnMgdGVybXMNClRlc3RzIGlmIHRoZSBlZmZlY3Qgb2YgTk9UIHRyZWF0aW5nIHdpdGggVVZCIHZzLiB0cmVhdGluZyB3aXRoIFVWQiBpcyBkaWZmZXJlbnQgYXQgV2VlayAxNSBjb21wYXJlZCB0byBXZWVrIDI6ICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV9yZXN1bHRzX2ludF9jb25fdXZifQ0KcmVzX2ludF9jb25fdXZiX3dlZWsgPC0gcmVzdWx0cyhkZHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gInRpbWUxNXcudHJ0Q09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfaW50X2Nvbl91dmJfd2VlayA8LSByZXNfaW50X2Nvbl91dmJfd2Vla1tvcmRlcihyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpwcmludChyZXNfaW50X2Nvbl91dmJfd2VlaykNCnN1bW1hcnkocmVzX2ludF9jb25fdXZiX3dlZWspDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KcHJpbnQocGxvdE1BKHJlc19pbnRfY29uX3V2Yl93ZWVrLA0KICAgICAgICAgICAgIG1haW4gPSAiKENvbnRyb2wgdnMuIFVWQikgeCBUSW1lIEludGVyYWN0aW9uIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOSkpDQoNCmBgYA0KDQpUZXN0cyBpZiB0aGUgZWZmZWN0IG9mIHRyZWF0aW5nIHdpdGggVVZCK1NGTiB2cy4gdHJlYXRpbmcgd2l0aCBVVkIgaXMgZGlmZmVyZW50IGF0IFdlZWsgMTUgY29tcGFyZWQgdG8gV2VlayAyOiAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfcmVzdWx0c19pbnRfc2ZuX3V2Yn0NCnJlc19pbnRfc2ZuX3V2Yl93ZWVrIDwtIHJlc3VsdHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJ0aW1lMTV3LnRydFNGTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2ludF9zZm5fdXZiX3dlZWsgPC0gcmVzX2ludF9zZm5fdXZiX3dlZWtbb3JkZXIocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0KcHJpbnQocmVzX2ludF9zZm5fdXZiX3dlZWspDQpzdW1tYXJ5KHJlc19pbnRfc2ZuX3V2Yl93ZWVrKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCnByaW50KHBsb3RNQShyZXNfaW50X3Nmbl91dmJfd2VlaykpDQoNCiMgTk9URTogc2FtZSBhcyANCiMgcmVzIDwtIHJlc3VsdHMoZGRzLCANCiMgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KQ0KIyByZXMgPC0gcmVzW29yZGVyKHJlcyRwYWRqLCBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCiMgcmVzDQpgYGANCg0KKipOT1RFKio6IEJ5IGRlZmF1bHQsIHRoZSAqKnJlc3VsdHMoZGRzKSoqKiBwcmludHMgdGhlIHJlc3VsdHMgZm9yIHRoZSBsYXN0IGxldmVsIG9mIHRoZSBsYXN0IHRlcm0sIGkuZS4gaGVyZSBpdCB3YXMgZm9yIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybSBTRk4gdnMuIFVWQiBhdCBXZWVrIDE1IHZzLiBXZWVrIDIuDQogICAgICAgDQojIEdlbmVzIHdpdGggYm90aCBpbnRlcmFjdGlvbnMgYmVpbmcgc2lnbmlmaWNhbnQNCmBgYHtyIHNpZ25faW50fQ0KbGdlbmUuY29uIDwtIHVuaXF1ZShyZXNfaW50X2Nvbl91dmJfd2Vla0Byb3duYW1lc1tyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xXSkNCmxnZW5lLnNmbiA8LSB1bmlxdWUocmVzX2ludF9zZm5fdXZiX3dlZWtAcm93bmFtZXNbcmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMV0pDQpsZ2VuZSA8LSBsZ2VuZS5jb25bbGdlbmUuY29uICVpbiUgbGdlbmUuc2ZuXQ0KbGdlbmUgPC0gbGdlbmVbIWlzLm5hKGxnZW5lKV0NCmxnZW5lDQpgYGANCg0KICAgICAgIA0KUGxvdCBvZiBERVNlcS1ub3JtYWxpemVkY291bnRzIG9mIGdlbmVzIHdpdGggc21hbGxlc3QgYWRqdXN0ZWQgcC12YWx1ZSBmb3IgdGhlIGludGVyYWN0aW9uIHRlcm06ICAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfdG9wOV9kZXNlcW5vcm0sIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IikpDQpkcDEkR2VuZWlkIDwtIGZhY3RvcihkcDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGdlbmUpDQpkcDFbLCBtdSA6PSBtZWFuKGNvdW50LA0KICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLA0KICAgIGJ5ID0gYygiR2VuZWlkIiwNCiAgICAgICAgICAgInRydCIsDQogICAgICAgICAgICJ0aW1lIildDQpkbXUgPC0gdW5pcXVlKGRwMVssIC1jKCJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAiY291bnQiKV0pDQoNCnAxIDwtIGdncGxvdChkcDEsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQogICAgICANCkNvbXBhcmUgdG8gdGhlIHBsb3Qgb2YgVFBNLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgd2l0aCBzbWFsbGVzdCBhZGp1c3RlZCBwLXZhbHVlIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybTogICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV90cG1ub3JtLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCiMgRXhhbWluZSBUUE0gdmFsdWVzIGZvciB0aGUgc2FtZSBnZW5lcw0KdG1wIDwtIHRwbVtHZW5laWQgJWluJSBsZ2VuZSwgXQ0KdG1wJEdlbmVpZCA8LSBmYWN0b3IodG1wJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lKQ0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KdG1wIDwtIG1lcmdlKGRtZXRhLA0KICAgICAgICAgICAgIHRtcCwNCiAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQ0KDQpwMSA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywNCiAgICAgICAgICAgICAgICAgeSA9IFRQTSwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBUcmVhdG1lbnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKQ0KcGxvdChwMSkNCmBgYA0KDQojIFNlc3Npb24gSW5mb3JtYXRpb24NCmBgYHtyIGluZm8sZXZhbD1UUlVFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBg